package com.nowcoder.community.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.nowcoder.community.dao.elasticsearch.DiscussPostRepository;
import com.nowcoder.community.entity.DiscussPost;
import com.nowcoder.community.service.ElasticsearchService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

/**
 * @author bombax
 * @date 2024/10/2
 */
@Service
public class ElasticsearchServiceImpl implements ElasticsearchService {
    @Resource
    private DiscussPostRepository discussPostRepository;

    @Resource
    private ElasticsearchClient elasticsearchClient;

    @Override
    public void saveDiscussPost(DiscussPost post) {
        discussPostRepository.save(post);
    }

    @Override
    public void deleteDiscussPost(int id) {
        discussPostRepository.deleteById(id);
    }

    @Override
    public Map<String, Object> searchDiscussPost(String keyword, int current, int limit) {
        SearchResponse<DiscussPost> searchResponse;
        try {
            searchResponse = elasticsearchClient.search(builder -> builder
                            .query(queryBuilder -> queryBuilder
                                    .multiMatch(multiMatchQueryBuilder -> multiMatchQueryBuilder
                                            .query(keyword)
                                            .fields("title", "content"))
                            )
                            .highlight(highlightBuilder -> highlightBuilder
                                    .preTags("<em>")
                                    .postTags("</em>")
                                    .requireFieldMatch(true)
                                    .fields("title", highlightFieldBuilder -> highlightFieldBuilder)
                                    .fields("content", highlightFieldBuilder -> highlightFieldBuilder)
                            )
                            .from(current)
                            .size(limit)
                            .sort(sortOptionsBuilder -> sortOptionsBuilder
                                    .field(fieldSortBuilder -> fieldSortBuilder
                                            .field("type").order(SortOrder.Desc)
                                            .field("score").order(SortOrder.Desc)
                                            .field("createTime").order(SortOrder.Desc))
                            )
                    , DiscussPost.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        List<DiscussPost> postList = getPostList(limit, searchResponse);
        Map<String, Object> result = new HashMap<>();
        result.put("postList", postList);
        result.put("total", searchResponse.hits().total() != null ? (int) searchResponse.hits().total().value() : 0);
        return result;
    }

    private static List<DiscussPost> getPostList(int limit, SearchResponse<DiscussPost> searchResponse) {
        List<Hit<DiscussPost>> hits = searchResponse.hits().hits();

        if(hits == null || hits.isEmpty()) {
            return null;
        }

        List<DiscussPost> list = new ArrayList<>(limit);
        for (Hit<DiscussPost> hit : hits) {
            DiscussPost post = hit.source();
            Map<String, List<String>> highlight = hit.highlight();
            if (Objects.nonNull(highlight.get("title"))) {
                post.setTitle(highlight.get("title").get(0));
            }
            if (Objects.nonNull(highlight.get("content"))) {
                post.setContent(highlight.get("content").get(0));
            }
            list.add(post);
        }
        return list;
    }
}
